package com.itheima.health.security.intercept;

import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import com.itheima.health.security.annotation.MySecurity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;

/**
 * @author ：leaflei
 * @date ：Created in 2022年08月05日
 * @version: 1.0
 * @description ： 自定义权限拦截器
 */
@Slf4j
@Component
public class SecurityInterceptor extends HandlerInterceptorAdapter {

    //设置路径白名单
    String[] auths = new String[]{
            "/user/login",
            "/user/logout",
            "/common/**",
            "/mobile/**"
    };


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("=====================权限拦截启动=====================");
        String requestURI = request.getRequestURI();
        log.info("拦截的路径 ===> {}", requestURI);
        //判断这个路径是否在白名单（不需要拦截）
        if (checkAuthUrl(requestURI)) {
            //如果这个路径在白名单中，直接放行
            return true;
        }
        //不在白名单中的需要登录访问
        Object user = request.getSession().getAttribute("user");
        //如果已经登录，鉴权
        if (user != null) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            //在方法上获取注解
            MySecurity permission = handlerMethod.getMethodAnnotation(MySecurity.class);
            //判断方法上是否存在注解
            if (permission == null) {
                //方法不存在则在类上寻找注解则在类上寻找注解
                permission = handlerMethod.getBeanType().getAnnotation(MySecurity.class);
            }
            //没有添加权限注解的直接跳过允许访问
            if (permission == null) {
                log.info("不需要鉴权 直接放行 ===> {}", requestURI);
                return true;
            }
            //获取注解的属性
            String[] strings = permission.value();
            //获取当前用户的所有角色信息
            User users = (User) user;
            Set<Role> roles = users.getRoles();
            //判断这个用户是否拥有响应的角色属性
            for (Role role : roles) {
                log.info("用户拥有的角色 ===> {}", role.getKeyword());
                for (String string : strings) {
                    log.info("访问需要的角色 ==={}", string);
                    if (role.getKeyword().equals(string)) {
                        log.info("该用户拥有访问权限，放行 ===>{}", requestURI);
                        return true;
                    }
                }
            }
            //无权访问
            Result result = new Result(false, "权限不足");
            //返回数据
            setReturn(request,response,result);
        } else {
            //返回未登录提示
            Result result = new Result(false, "请重新登录");
            //返回数据
            setReturn(request,response,result);
        }
        //不放行
        return false;
    }

    //返回页面数据
    private static void setReturn(HttpServletRequest request, HttpServletResponse response,Result result) throws IOException {
        //设置响应头
        response.setContentType("application/json;charset=utf-8");
        //转换为json字符串
        String string = JSON.toJSONString(result);
        //返回数据
        response.getWriter().write(string);
    }

    //URL路径匹配校验
    private boolean checkAuthUrl(String requestURI) {
        // 使用Spring提供的路径匹配器
        AntPathMatcher pathMatcher = new AntPathMatcher();
        //循环判断所有路径规则
        for (String url : auths) {
            if (pathMatcher.match(url, requestURI)) {
                log.info("[权限过滤器，匹配是白名单:uri:{}]", requestURI);
                return true;
            }
        }
        //不是白名单
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("SecurityInterceptor ===> postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("SecurityInterceptor ===> afterCompletion");
    }
}
